home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Megadoom II
/
MEGADOOM II - iso.7z
/
MEGADOOM II.ISO
/
doom
/
editors
/
wadfile
/
warm11
/
warm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-17
|
47KB
|
1,142 lines
/******************************************************************************
PROGRAM: WARM.C
WRITTEN BY: Robert Fenske, Jr. (rfenske@swri.edu)
Southwest Research Institute
Electromagnetics Division
6220 Culebra
San Antonio, Texas 78238-5166
CREATED: May 1994
DESCRIPTION: This program is the WAD Auxiliary Resource Manipulator.
It extracts data from a DOOM-related PWAD, IWAD, or
VERDA patch file and builds the BSP-related structures
segs, subsectors, and nodes; the blockmap structure;
and the reject structure. It can build these
structures for all the levels in the input file, or for
a specific level found in the input file. The main
command line arguments are as follows:
[-e#m#] [-z] [-x=<list>] [-n] [-b] [-r]
<input file> [output file]
where -e#m# specifies a particular level within the
input file (use -map## for DOOM II WAD files), -z
specifies to generate a zero-filled reject block (much
faster than building a full REJECT), -x=<list>
specifies a sector exception list for the reject block,
input file is the input filename, and output file is
the optional output filename. If no output file is
specified, the input file is rewritten with the new
data.
It also contains various functions to manipulate
various resources in a DOOM-related IWAD, PWAD, or
VERDA patch file.
This program has been compiled and run under SunOS
using cc(1), under MS-DOS using DJGPP (GCC) and
under OS/2 using C/Set++.
DOOM is a trademark of id Software, Inc.
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !defined(__OS2__)
#include <values.h>
#endif
#include <math.h>
#include <time.h>
#include "dmglobal.i"
#define SOFTVER 1.1 /* software version */
#define SOFTDATE "January 1995" /* software version date */
#define RESOURCES_NEEDED ((long)((1<<THINGS)|(1<<LINES)|(1<<SIDES)|(1<<VERTS)|\
(1<<SEGS)|(1<<SSECTS)|(1<<NODES)|(1<<SECTS)))
#define help(t) printf("%*s %s\n",(int)strlen(prog),"",(t))
#define is_furniture(t) \
((0x001<=(t).item&&(t).item<=0x004) ||/* player starts */\
(t).item==0x00E || /* teleport */\
(0x019<=(t).item&&(t).item<=0x039) ||/* various columns, */\
(0x03B<=(t).item&&(t).item<=0x03F) ||/* skulls, prisoners */\
(t).item==0x046 || /* burning barrel */\
(0x048<=(t).item&&(t).item<=0x051) ||/* various hanging */\
(t).item==0x7EC || (t).item==0x7F3)/* light post,barrel */
#define is_deathmatch(t) ((t).item==0x00B) /* deathmatch */
#define is_creature(t) ((t).item==0x0007 || /* spider demon */\
(t).item==0x0009 || /* former sargent */\
(t).item==0x0010 || /* cyborg baron */\
(t).item==0x003A || /* spectre */\
(t).item==0x0040 || /* archvile */\
(t).item==0x0041 || /* former commando */\
(t).item==0x0042 || /* revenant */\
(t).item==0x0043 || /* mancubus */\
(t).item==0x0044 || /* arachnotron */\
(t).item==0x0045 || /* hell knight */\
(t).item==0x0047 || /* pain elemental */\
(t).item==0x0054 || /* Wolfenstein SS */\
(t).item==0x0057 || /* spawn spot */\
(t).item==0x0058 || /* boss brain */\
(t).item==0x0059 || /* boss shooter */\
(t).item==0x0BB9 || /* imp */\
(t).item==0x0BBA || /* pink demon */\
(t).item==0x0BBB || /* baron of hell */\
(t).item==0x0BBC || /* former human */\
(t).item==0x0BBD || /* cacodemon */\
(t).item==0x0BBE) /* lost soul */
#define is_boss(t) ((t).item==0x0007 || /* spider demon */\
(t).item==0x0010 || /* cyborg baron */\
(t).item==0x0BBB) /* baron of hell */
#define is_weapon(t) ((t).item==0x0052 || /* super shotgun */\
(t).item==0x07D1 || /* shotgun */\
(t).item==0x07D2 || /* chain gun */\
(t).item==0x07D3 || /* rocket launcher */\
(t).item==0x07D4 || /* plasma rifle */\
(t).item==0x07D5 || /* chainsaw */\
(t).item==0x07D6) /* BFG9000 */
#define Things ((DOOM_THING *)iwad->data[e+THINGS])
#define Lines ((DOOM_LINE *)iwad->data[e+LINES])
#define Sides ((DOOM_SIDE *)iwad->data[e+SIDES])
#define Verts ((DOOM_VERT *)iwad->data[e+VERTS])
#define Segs ((DOOM_SEGS *)iwad->data[e+SEGS])
#define Ssecs ((DOOM_SSECTOR *)iwad->data[e+SSECTS])
#define Nodes ((DOOM_NODE *)iwad->data[e+NODES])
#define Sects ((DOOM_SECTOR *)iwad->data[e+SECTS])
#define Rejects ((DOOM_REJECT *)iwad->data[e+REJECTS])
#define Blockmaps ((DOOM_BLOCKMAP *)iwad->data[e+BLKMAPS])
#define NThings iwad->count[e+THINGS]
#define NLines iwad->count[e+LINES]
#define NSides iwad->count[e+SIDES]
#define NVerts iwad->count[e+VERTS]
#define NSegs iwad->count[e+SEGS]
#define NSsecs iwad->count[e+SSECTS]
#define NNodes iwad->count[e+NODES]
#define NSects iwad->count[e+SECTS]
#define NRejects iwad->count[e+REJECTS]
#define NBlockmaps iwad->count[e+BLKMAPS]
#if defined(sun)
extern void srand48();
extern double drand48();
#elif (__OS2__)
#include <limits.h>
#define srand48(s) srand(s)
#define drand48() ((double)rand()/(double)SHRT_MAX)
#else
#define srand48(s) srandom(s)
#define drand48() ((double)random()/(double)MAXINT)
#endif
#if defined(ANSI_C)
int dmit(int ver,register DOOM_THING *things,long nthings,DOOM_SECTOR *sects,
long nsects);
int _Optlink rand_xy_sort(register const void *thing1,
register const void *thing2);
int _Optlink rand_item_sort(register const void *thing1,
register const void *thing2);
int rand_thing(long seed, register DOOM_THING *things, long nthings);
int flip(DOOM_THING *things, long nthings, DOOM_VERT *verts, long nverts,
DOOM_LINE *lines, long nlines, DOOM_NODE *nodes, long nnodes,
DOOM_SEGS *segs, long nsegs);
int shift(int dx,int dy,int dz,DOOM_THING *things, long nthings,
DOOM_VERT *verts, long nverts, DOOM_NODE *nodes, long nnodes,
DOOM_SECTOR *sects, long nsects);
int emstat(register WAD_INFO *iwad, register int e);
int directory(register WAD_INFO *iwad);
int extract(register WAD_INFO *iwad, char *list);
int substitute(register WAD_INFO *iwad, char *list);
int merge(register WAD_INFO *iwad, int e, char *list);
#endif
/******************************************************************************
ROUTINE: main(ac,av)
WRITTEN BY: Robert Fenske, Jr.
CREATED: Apr. 1994
DESCRIPTION: This routine processes the command line arguments
and executes the appropriate manipulation function.
******************************************************************************/
#if defined(ANSI_C)
int main(int ac, char *av[])
#else
int main(ac,av)
int ac;
char *av[];
#endif
{
static char func[256] = ""; /* manipulating function(s) */
static char rxcpt_list[256] = ""; /* REJECT exception list */
static char extract_list[256] = "", /* resource extraction list */
subst_list[256] = "", /* rsrce substitution list */
merge_list[256] = ""; /* merge file list */
char *ifile = NULL, *ofile = NULL; /* input/output filenames */
char *prog; /* program name */
WAD_INFO *iwad, *owad; /* input/output info blocks */
boolean show_help = FALSE; /* whether to display help */
boolean good = FALSE; /* whether read/write worked */
int epdo = 0, mpdo = 0; /* specific ep/map to do */
int outtype = 0; /* specified output type */
boolean zeroflag = 0; /* don't make zero REJECT */
int dmver = 1; /* deathmatch version # */
long seed; /* randomize seed */
int dx = 0, dy = 0, dz = 0; /* shift by dx, dy, dz */
int e = -1; /* current directory entry */
time_t begintime, totaltime, hours, mins, secs;
register int a;
begintime = time(NULL);
setbuf(stdout,(char *)NULL); /* make stdout unbuffered */
printf("\n\t\t\tWAD Auxiliary Resource Manipulator\n");
printf(" Version %3.1f of %s by Robert Fenske, Jr (rfenske@swri.edu)\n\
Ported to OS/2 2.1 by Mark K. Mathews (mark.mathews@channel1.com)\n\n",
SOFTVER,SOFTDATE);
for (a = 1; a < ac; a++) { /* scan all arguments */
if (av[a][0] == '-') { /* optional argument */
if (2 == sscanf(av[a],"-%*[Ee]%d%*[Mm]%d",&epdo,&mpdo))
;
else if (1 == sscanf(av[a],"-map%d",&mpdo))
epdo = 4;
else if (1 == sscanf(av[a],"-MAP%d",&mpdo))
epdo = 4;
else if (0 == strcmp(av[a],"-z"))
zeroflag = 1;
else if (1 == sscanf(av[a],"-x=%s",rxcpt_list))
;
else if (0 == strcmp(av[a],"-n"))
strcat(func,"nodes");
else if (0 == strcmp(av[a],"-b"))
strcat(func,"blockmap");
else if (0 == strcmp(av[a],"-r"))
strcat(func,"reject");
else if (1 == sscanf(av[a],"-dmit=%d",&dmver))
strcat(func,"dmit");
else if (1 == sscanf(av[a],"-rand=%ld",&seed))
strcat(func,"rand");
else if (0 == strcmp(av[a],"-flip"))
strcat(func,"flip");
else if (2 <= sscanf(av[a],"-shift=%d,%d,%d",&dx,&dy,&dz))
strcat(func,"shift");
else if (0 == strcmp(av[a],"-emstat"))
strcat(func,"emstat");
else if (0 == strcmp(av[a],"-dir"))
strcat(func,"dir");
else if (1 == sscanf(av[a],"-e=%s",extract_list))
;
else if (1 == sscanf(av[a],"-s=%s",subst_list))
;
else if (1 == sscanf(av[a],"-m=%s",merge_list))
;
else if (1 == sscanf(av[a],"-o=%d",&outtype))/* this isn't in help */
;
else
show_help = TRUE;
}else if (ifile == NULL)
ifile = ofile = av[a]; /* get input filename */
else
ofile = av[a]; /* get output filename */
}
prog = strrchr(av[0],'\\');
if (prog == NULL) prog = strrchr(av[0],'/');
if (prog != NULL) prog++;
else prog = av[0];
if (strrchr(prog,'.') != NULL) *strrchr(prog,'.') = '\0';
if (ifile == NULL || show_help) { /* show now to do corectly */
printf("%s [-e#m#] [-z] [-x=<slist>] [-n] [-b] [-r]",prog);
printf(" <input file> [output file]\n");
help("[-dmit=<#>] [-rand=<#>] [-flip] [-shift=<dx,dy[,dz]>] [-emstat]");
help("[-dir] [-e=<rlist>] [-s=<flist>] [-m=<flist>]\n");
help("-e#m# specify level to process; otherwise does all levels in");
help(" input file (use -map## for DOOM II WAD files)");
help("-z build zero-filled REJECT--much faster than full REJECT");
help("-x=<slist> specify exceptions for REJECT; <slist> is <s>,... where");
help(" <s> is <sector #>[-<sector #>]; this forces a 1 for");
help(" each sector pair or for a sector against all others");
help("-n build nodes");
help("-b build blockmap");
help("-r build reject");
help("<input file> PWAD, IWAD, or VERDA patch file");
help("<output file> output file; if none specified, input file is rewritten");
help(" ");
help("defaults to -n -b -r if none of the following options is specified;");
help("otherwise, perform specified function");
help(" ");
help("press Enter to see other options"); /* could be more sophisti- */
(void)getchar(); /* cated, but won't bother */
help(" ");
help("-dmit=<#> \"deathmatch-ize\" level for version 1 or 2");
help("-rand=<#> swap creatures, bonuses, deathmatch starts positions");
help(" randomly using specified seed");
help("-flip flip level about Y-axis (make mirror image)");
help("-shift=<dx,dy,dz> shift level by dx, dy, dz");
help("-emstat display level statistics");
help("-dir display resource directory");
help("-e=<rlist> extract comma-separated named resources from input");
help(" file to output file; resources E#M# or MAP## extract");
help(" all data for that level; if starts with !, extract");
help(" all resources not named");
help("-s=<flist> substitute resources in input file with resources in");
help(" comma-separated PWAD, IWAD, or VERDA patch files");
help("-m=<flist> merge comma-separated PWAD, IWAD, or VERDA patch");
help(" files with input file: matching E#M# level data is");
help(" merged, unique resources are added\n");
help("dir, extract, substitute, and merge are mutually exclusive with all");
help("other functions and ignore any -e#m# or -map## option");
printf("\n\t\t\tWAD Auxiliary Resource Manipulator\n");
printf(" Version %3.1f of %s by Robert Fenske, Jr (rfenske@swri.edu)\n\
Ported to OS/2 2.1 by Mark K. Mathews (mark.mathews@channel1.com)\n",
SOFTVER,SOFTDATE);
return 1;
}
if (strstr(func,"dir") != NULL && strcmp(func,"dir") != 0) {
fprintf(stderr,
"directory function is mutually exclusive with other functions\n");
return 1;
}
if (strlen(extract_list) > 0 && strlen(func) > 0) {
fprintf(stderr,
"extract function is mutually exclusive with other functions\n");
return 1;
}
if (strlen(subst_list) > 0 && strlen(func) > 0) {
fprintf(stderr,
"sustitute function is mutually exclusive with other functions\n");
return 1;
}
if (strlen(merge_list) > 0 && strlen(func) > 0) {
fprintf(stderr,
"merge function is mutually exclusive with other functions\n");
return 1;
}
if ((strlen(extract_list) > 0 || strlen(merge_list) > 0)
&& strcmp(ifile,ofile) == 0) {
fprintf(stderr,"output file must be different from input file\n");
return 1;
}
if (strlen(extract_list) == 0 && /* if no specified functions */
strlen(subst_list) == 0 && /* do default of building */
strlen(merge_list) == 0 && /* nodes, blockmap, reject */
strlen(func) == 0)
strcpy(func,"nodes,blockmap,reject");
iwad = wad_open(ifile,TRUE,FALSE); /* open input file */
if (iwad == NULL) {
fprintf(stderr,"unable to open %s for reading\n",ifile);
return 1;
}
if (iwad->type == 0) { /* not a valid file */
fprintf(stderr,"%s is not a PWAD, IWAD, nor VERDA patch file\n",ifile);
return 1;
}
if ((owad = wad_open(ofile,FALSE,strcmp(ifile,ofile)==0)) == NULL) {
fprintf(stderr,"unable to open %s for writing\n",ofile);
return 1;
}
owad->type = iwad->type; /* set output file type */
if (outtype && strcmp(ifile,ofile)) owad->type = outtype;
do { /* process file until done */
printf("\nReading %s file %s...",iwad->type==1?"WAD":"patch",ifile);
for (e++; e < iwad->head.count; e++) /* find next map level */
if (strstr(func,"dir") != NULL ||
strlen(extract_list) || strlen(subst_list) || strlen(merge_list))
break;
else
if ((2==sscanf(iwad->dir[e].name,"E%dM%d",&iwad->ep,&iwad->mp) ||
1==sscanf(iwad->dir[e].name,"MAP%d",&iwad->mp) && (iwad->ep=4)==4)
&&
(epdo == 0 && mpdo == 0 || /* find any next level */
epdo == iwad->ep && mpdo == iwad->mp))/* find specific nxt lvl */
break;
good = wad_read(iwad,e,RESOURCES_NEEDED);
if (good) { /* process new level data */
printf("done\n");
if (strstr(func,"nodes") != NULL) {
DOOM_LINE *lines = Lines;
DOOM_VERT *verts = Verts;
DOOM_SEGS *segs = Segs;
DOOM_SSECTOR *ssecs = Ssecs;
DOOM_NODE *nodes = Nodes;
printf("Building BSP tree for level E%dM%d...",iwad->ep,iwad->mp);
nodes_make(&nodes,&NNodes,&ssecs,&NSsecs,&segs,&NSegs,&verts,&NVerts,
&lines,&NLines);
resource_update(iwad,e+VERTS,verts,NVerts);/* vertices modified */
resource_update(iwad,e+SEGS,segs,NSegs);/* these three created */
resource_update(iwad,e+SSECTS,ssecs,NSsecs);
resource_update(iwad,e+NODES,nodes,NNodes);
printf("%ld nodes, %ld segs \n",NNodes,NSegs);
}
if (strstr(func,"blockmap") != NULL) {
DOOM_BLOCKMAP *blockmaps = Blockmaps;
printf("Building BLOCKMAP for level E%dM%d...",iwad->ep,iwad->mp);
NBlockmaps = blockmap_make(&blockmaps,Lines,NLines,Verts);
resource_update(iwad,e+BLKMAPS,blockmaps,NBlockmaps);
printf("%d x %d blocks\n",blockmaps[2],blockmaps[3]);
}
if (strstr(func,"reject") != NULL) {
DOOM_REJECT *rejects = Rejects;
printf("Building REJECT for level E%dM%d...",iwad->ep,iwad->mp);
if (Blockmaps == NULL) wad_read(iwad,e,1<<BLKMAPS);
NRejects = reject_make(&rejects,zeroflag,rxcpt_list,
Lines,NLines,Sides,Verts,Blockmaps);
resource_update(iwad,e+REJECTS,rejects,NRejects);
printf(zeroflag?"zeroed\n":"done\n");
}
if (strstr(func,"dmit") != NULL) {
printf("Deathmatch-izing (V%d.0) level E%dM%d...",
dmver,iwad->ep,iwad->mp);
dmit(dmver,Things,NThings,Sects,NSects);
resource_update(iwad,e+THINGS,Things,NThings);
resource_update(iwad,e+SECTS,Sects,NSects);
printf("done\n");
}
if (strstr(func,"rand") != NULL) {
printf("Randomizing things on level E%dM%d...",iwad->ep,iwad->mp);
rand_thing(seed,Things,NThings);
resource_update(iwad,e+THINGS,Things,NThings);
printf("done\n");
}
if (strstr(func,"flip") != NULL) {
DOOM_BLOCKMAP *blockmaps; /* new BLOCKMAP for flip */
printf("Flipping level E%dM%d...",iwad->ep,iwad->mp);
flip(Things,NThings,Verts,NVerts,Lines,NLines,Nodes,NNodes,Segs,NSegs);
NBlockmaps = blockmap_make(&blockmaps,Lines,NLines,Verts);
resource_update(iwad,e+THINGS,Things,NThings);
resource_update(iwad,e+VERTS,Verts,NVerts);
resource_update(iwad,e+LINES,Lines,NLines);
resource_update(iwad,e+NODES,Nodes,NNodes);
resource_update(iwad,e+SEGS,Segs,NSegs);
resource_update(iwad,e+BLKMAPS,blockmaps,NBlockmaps);
printf("done\n");
}
if (strstr(func,"shift") != NULL) {
DOOM_BLOCKMAP *blockmaps; /* new BLOCKMAP for shift */
printf("Shifting level E%dM%d...",iwad->ep,iwad->mp);
shift(dx,dy,dz,Things,NThings,Verts,NVerts,Nodes,NNodes,Sects,NSects);
NBlockmaps = blockmap_make(&blockmaps,Lines,NLines,Verts);
resource_update(iwad,e+THINGS,Things,NThings);
resource_update(iwad,e+VERTS,Verts,NVerts);
resource_update(iwad,e+NODES,Nodes,NNodes);
resource_update(iwad,e+SECTS,Sects,NSects);
resource_update(iwad,e+BLKMAPS,blockmaps,NBlockmaps);
printf("done\n");
}
if (strstr(func,"emstat") != NULL) {
printf("Statistics for level E%dM%d...\n",iwad->ep,iwad->mp);
emstat(iwad,e);
if (strcmp(func,"emstat") == 0) continue;
}
if (strstr(func,"dir") != NULL) {
printf("Directory for %s...\n",ifile);
directory(iwad);
e = iwad->head.count; /* don't read any more */
continue;
}
if (strlen(extract_list) > 0) {
printf("Extracting from %s...",ifile);
good = extract(iwad,extract_list);
printf(good?"done\n":"failed\n");
e = iwad->head.count; /* don't read any more */
}
if (strlen(subst_list) > 0) {
printf("Substituting resources in %s with...",ifile);
good = substitute(iwad,subst_list);
printf(good?"done\n":"failed\n");
e = iwad->head.count; /* don't read any more */
}
if (strlen(merge_list) > 0) {
printf("Merging %s with...",ifile);
good = merge(iwad,e,merge_list);
printf(good?"done\n":"failed\n");
e = iwad->head.count; /* don't read any more */
}
}else if (iwad->head.count <= e) /* no more in file */
printf("no more levels\n");
else /* oops: bogus data */
printf("failed\n");
if (good) { /* if processed, write it */
printf("Writing %s file %s...",owad->type==1?"WAD":"patch",ofile);
good = wad_write(owad,iwad);
printf(good?"done\n":"failed\n");
}
} while (good);
wad_close(owad);
wad_close(iwad);
if (strstr(func,"nodes") != NULL || /* display processing time */
strstr(func,"reject") != NULL) { /* for compute intensive */
totaltime = time(NULL) - begintime; /* operations */
hours = totaltime/3600;
mins = (totaltime-(hours*3600))/60;
secs = totaltime-(hours*3600)-(mins*60);
printf("Processing completed in ");
if (hours) printf("%ld hours, ",hours);
if (hours || mins) printf("%ld minutes, ",mins);
printf("%ld seconds\n",secs);
}
return 0; /* everything is okay */
}
/******************************************************************************
ROUTINE: dmit(ver,things,nthings,sects,nsects)
WRITTEN BY: Robert Fenske, Jr.
CREATED: Mar. 1994
DESCRIPTION: This routine deathmatch-izes the THINGS and SECTORS
resources.
******************************************************************************/
#if defined(ANSI_C)
int dmit(int ver,register DOOM_THING *things,long nthings,DOOM_SECTOR *sects,
long nsects)
#else
int dmit(ver,things,nthings,sects,nsects)
int ver;
register DOOM_THING *things;
long nthings;
DOOM_SECTOR *sects;
long nsects;
#endif
{
static int subst[][2] = { /* item substitutions */
{0x0002, 0x07E6}, /* player 2 --> invulner sph */
{0x0003, 0x07E7}, /* player 3 --> berzerk pk */
{0x0004, 0x07E8}, /* player 4 --> blur sphere */
{0x0005, 0x07DD}, /* blue key --> soul sphere */
{0x0006, 0x07E8}, /* yellow key --> blur sph */
{0x000A, 0x07DD}, /* explod being --> soul sph */
{0x000C, 0x07DD}, /* explod being --> soul sph */
{0x000D, 0x07E6}, /* red key --> invulner sph */
{0x000F, 0x0008}, /* dead marine --> backpack */
{0x0012, 0x07E3}, /* dead fmr hu --> cmbt arm */
{0x0013, 0x07E6}, /* dead fmr sa --> invl sph */
{0x0014, 0x07E2}, /* dead fmr sa --> sec armor */
{0x0015, 0x07E8}, /* dead demon --> blur sph */
{0x0016, 0x07E7}, /* dead caco --> berzerk pk */
{0x0017, 0x07E7}, /* dead skull --> berzerk pk */
{0x0018, 0x0008}, /* bloody goo --> backpack */
{0x0022, 0x07DB}, /* candle --> stimpak */
{0x0023, 0x07F3}, /* candelabra --> barrel */
{0x0026, 0x0011}, /* red skull ky --> ener pk */
{0x0027, 0x0011}, /* yel skull ky --> ener pk */
{0x0028, 0x0011}, /* blu skull ky --> ener pk */
{0x07D7, 0x0800}, /* clip --> box of ammo */
{0x07D8, 0x0801}, /* shells --> box of shells */
{0x07DA, 0x07FE}, /* rocket --> box o rockets */
{0x07DE, 0x07DB}, /* bonus health --> stimpak */
{0x07DF, 0x07E2}, /* bonus armor --> armor */
{0x07E9, 0x07E3}, /* rad suit --> combat arm */
{0x07FF, 0x0011}, /* energy cell --> ener pk */
{0x07EA, 0x07DD}, /* map --> soul sphere */
{0x07EC, 0x07DB} /* light post --> stimpak */
};
int caco = 0, troop = 0, sarg = 0, skull = 0;
int chainsaw = 0, chaingun = 0, plasma = 0, launcher = 0, bfg = 0;
register int i, s;
for (i = 0; i < nthings; i++) {
things[i].flag = 0x17; /* all skills, net play only */
if (ver == 1) {
for (s = 0; s < numelm(subst); s++) /* do the substitutions */
if (things[i].item == subst[s][0])
things[i].item = subst[s][1];
}else {
if (things[i].item == 0x07DB || things[i].item == 0x07DC)
things[i].item = 0x07DE;
}
if (is_creature(things[i]))
if (caco++ < 2) things[i].item = 0x0BBD;
else if (troop++ < 15) things[i].item = 0x0BBC;
else if (sarg++ < 10) things[i].item = 0x0009;
else if (skull++ < 15) things[i].item = 0x0BBE;
else things[i].item = ver==1? 0x07DC : 0x07DE;
if (is_weapon(things[i]))
if (chainsaw < 1) chainsaw++, things[i].item = 0x07D5;
else if (chaingun < 1) chaingun++, things[i].item = 0x07D2;
else if (plasma < 1) plasma++, things[i].item = 0x07D4;
else if (chaingun < 2) chaingun++, things[i].item = 0x07D2;
else if (plasma < 2) plasma++, things[i].item = 0x07D4;
else if (launcher < 1) launcher++, things[i].item = 0x07D3;
else if (bfg < 1) bfg++, things[i].item = 0x07D6;
else things[i].item = 0x07D1;
}
for (i = 0; i < nsects; i++) {
if (sects[i].property == 0x07) { /* remove "acid" */
sects[i].property = 0x00;
strcpy(sects[i].floor_desc,"FLAT1_1");
}else if (sects[i].property == 0x05) { /* remove health hit */
sects[i].property = 0x00;
strcpy(sects[i].floor_desc,"FWATER1");
}
}
return TRUE;
}
/******************************************************************************
ROUTINE: rand_xy_sort(thing1,thing2)
WRITTEN BY: Robert Fenske, Jr.
CREATED: June 1994
DESCRIPTION: This routine is the comparison function for qsort().
It orders the things by their coordinates.
******************************************************************************/
#if defined(ANSI_C)
int _Optlink rand_xy_sort(register const void *thing1,
register const void *thing2)
#else
local int rand_xy_sort(thing1,thing2)
register DOOM_THING *thing1, *thing2;
#endif
{
DOOM_THING *t1 = (DOOM_THING *)thing1;
DOOM_THING *t2 = (DOOM_THING *)thing2;
int xdel = sgn(t1->x - t2->x);
int ydel = sgn(t1->y - t2->y);
return xdel != 0 ? xdel : ydel;
}
/******************************************************************************
ROUTINE: rand_item_sort(thing1,thing2)
WRITTEN BY: Robert Fenske, Jr.
CREATED: June 1994
DESCRIPTION: This routine is the comparison function for qsort().
It orders the things by their item types.
******************************************************************************/
#if defined(ANSI_C)
int _Optlink rand_item_sort(register const void *thing1,
register const void *thing2)
#else
local int rand_item_sort(thing1,thing2)
register DOOM_THING *thing1, *thing2;
#endif
{
DOOM_THING *t1 = (DOOM_THING *)thing1;
DOOM_THING *t2 = (DOOM_THING *)thing2;
return t1->item - t2->item;
}
/******************************************************************************
ROUTINE: rand_thing(seed,things,nthings)
WRITTEN BY: Robert Fenske, Jr.
CREATED: Mar. 1994
DESCRIPTION: This routine randomizes the order of the things in
the THINGS resource. It sorts the things by item type
and coordinates first so that the same seed will
always produce the same new order regardless of the
original input order. Deathmatch starts and all
"furniture" (barrels, lamps, etc) are never moved.
******************************************************************************/
#if defined(ANSI_C)
int rand_thing(long seed, register DOOM_THING *things, long nthings)
#else
int rand_thing(seed,things,nthings)
long seed;
register DOOM_THING *things;
long nthings;
#endif
{
int t1, t2;
DOOM_THING temp;
register DOOM_THING *items;
register int i, t;
qsort((char *)things,(int)nthings,sizeof *things,rand_xy_sort);
items = blockmem(DOOM_THING,nthings);
for (t = 0; t < nthings; t++) items[t] = things[t];
qsort((char *)items,(int)nthings,sizeof *items,rand_item_sort);
srand48((unsigned int)seed);
for (t = 0; t < nthings; t++) { /* scramble order here */
t1 = nthings*drand48(), t2 = nthings*drand48();
temp = things[t1], things[t1] = things[t2], things[t2] = temp;
t1 = nthings*drand48(), t2 = nthings*drand48();
temp = items[t1], items[t1] = items[t2], items[t2] = temp;
}
for (i = 0, t = 0; t < nthings; t++)
if (!is_deathmatch(things[t]) && !is_furniture(things[t])) {
while (is_deathmatch(items[i]) || is_furniture(items[i]))
i++;
things[t].item = items[i ].item; /* swapping gets new */
things[t].flag = items[i++].flag; /* (x,y) for thing */
}
blockfree(items);
return TRUE;
}
/******************************************************************************
ROUTINE: flip(things,nthings,verts,nverts,lines,nlines,
nodes,nnodes,segs,nsegs)
WRITTEN BY: Robert Fenske, Jr.
CREATED: Apr. 1994
DESCRIPTION: This routine flips the level about the Y axis, so
effectively reverses the level as far as the player is
concerned. Note that flipping about the X axis does
the same thing from the player's persective.
******************************************************************************/
#if defined(ANSI_C)
int flip(DOOM_THING *things, long nthings, DOOM_VERT *verts, long nverts,
DOOM_LINE *lines, long nlines, DOOM_NODE *nodes, long nnodes,
DOOM_SEGS *segs, long nsegs)
#else
int flip(things,nthings,verts,nverts,lines,nlines,nodes,nnodes,segs,nsegs)
DOOM_THING *things;
long nthings;
DOOM_VERT *verts;
long nverts;
DOOM_LINE *lines;
long nlines;
DOOM_NODE *nodes;
long nnodes;
DOOM_SEGS *segs;
long nsegs;
#endif
{
unsigned short tang;
register short temp;
register int i;
for (i = 0; i < nthings; i++) /* negate X coordinate */
things[i].x = -things[i].x;
for (i = 0; i < nverts; i++) /* negate X coordinate */
verts[i].x = -verts[i].x;
for (i = 0; i < nlines; i++) { /* swap from and to vertices */
temp = lines[i].fndx;
lines[i].fndx = lines[i].tndx;
lines[i].tndx = temp;
}
for (i = 0; i < nnodes; i++) {
nodes[i].x = -nodes[i].x; /* negate X coordinate */
nodes[i].xdel = -nodes[i].xdel; /* negate X offset */
temp = -nodes[i].rxmax; /* swap right and left */
nodes[i].rxmax = -nodes[i].lxmin; /* bounding box X */
nodes[i].lxmin = temp; /* coordinates: min for */
temp = -nodes[i].rxmin; /* max and negate */
nodes[i].rxmin = -nodes[i].lxmax;
nodes[i].lxmax = temp;
temp = nodes[i].rymax; /* swap right and left */
nodes[i].rymax = nodes[i].lymax; /* bounding box Y */
nodes[i].lymax = temp; /* min/max coordinates */
temp = nodes[i].rymin;
nodes[i].rymin = nodes[i].lymin;
nodes[i].lymin = temp;
temp = nodes[i].nndx[0]; /* swap node subtrees */
nodes[i].nndx[0] = nodes[i].nndx[1];
nodes[i].nndx[1] = temp;
}
for (i = 0; i < nsegs; i++) {
temp = segs[i].tndx; /* swap from and to vertices */
segs[i].tndx = segs[i].fndx;
segs[i].fndx = temp;
tang = -segs[i].angle; /* negate angle */
segs[i].angle = tang;
}
return TRUE;
}
/******************************************************************************
ROUTINE: shift(dx,dy,dz,things,nthings,verts,nverts,
nodes,nnodes,sects,nsects)
WRITTEN BY: Robert Fenske, Jr.
CREATED: Apr. 1994
DESCRIPTION: This routine shifts the level by dx, dy, dz.
******************************************************************************/
#if defined(ANSI_C)
int shift(int dx,int dy,int dz,DOOM_THING *things, long nthings,
DOOM_VERT *verts, long nverts, DOOM_NODE *nodes, long nnodes,
DOOM_SECTOR *sects, long nsects)
#else
int shift(dx,dy,dz,things,nthings,verts,nverts,nodes,nnodes,sects,nsects)
int dx, dy, dz;
DOOM_THING *things;
long nthings;
DOOM_VERT *verts;
long nverts;
DOOM_NODE *nodes;
long nnodes;
DOOM_SECTOR *sects;
long nsects;
#endif
{
register int i;
for (i = 0; i < nthings; i++) /* shift things coordinates */
things[i].x += dx, things[i].y += dy;
for (i = 0; i < nverts; i++) /* shift vertices coords */
verts[i].x += dx, verts[i].y += dy;
for (i = 0; i < nnodes; i++) { /* shift nodes coordinates */
nodes[i].x += dx, nodes[i].y += dy,
nodes[i].rxmin += dx, nodes[i].rymin += dy,
nodes[i].rxmax += dx, nodes[i].rymax += dy,
nodes[i].lxmin += dx, nodes[i].lymin += dy,
nodes[i].lxmax += dx, nodes[i].lymax += dy;
}
for (i = 0; i < nsects; i++) { /* shift sector heights */
sects[i].floor_ht += dz;
sects[i].ceil_ht += dz;
}
return TRUE;
}
/******************************************************************************
ROUTINE: emstat(iwad,e)
WRITTEN BY: Robert Fenske, Jr.
CREATED: June 1994
DESCRIPTION: This routine displays statistics about the input level.
******************************************************************************/
#if defined(ANSI_C)
int emstat(register WAD_INFO *iwad, register int e)
#else
int emstat(iwad,e)
register WAD_INFO *iwad;
register int e;
#endif
{
DIR_ENTRY *dir = &iwad->dir[e];
int mlv = -1; /* maximum line vertex */
short xmin, xmax, ymin, ymax;
short x, y;
int one_sided = 0; /* one-sided line count */
int secret = 0; /* secret sector count */
int special = 0; /* special sector count */
register int i;
for (i = 0; i < ALL; i++) /* get any missing resources */
if (iwad->data[e+i] == NULL) (void)wad_read(iwad,e,1L<<i);
xmin = ymin = (short)0x7FFF, xmax = ymax = (short)0x8000;
for (i = 0; i < NLines; i++) { /* find map min,max x,y */
x = Verts[Lines[i].fndx].x, y = Verts[Lines[i].fndx].y;
if (x < xmin) xmin = x;
if (y < ymin) ymin = y;
if (xmax < x) xmax = x;
if (ymax < y) ymax = y;
x = Verts[Lines[i].tndx].x, y = Verts[Lines[i].tndx].y;
if (x < xmin) xmin = x;
if (y < ymin) ymin = y;
if (xmax < x) xmax = x;
if (ymax < y) ymax = y;
if (mlv < Lines[i].fndx) mlv = Lines[i].fndx;/* find highest line vertex */
if (mlv < Lines[i].tndx) mlv = Lines[i].tndx;
one_sided += Lines[i].lsidndx == -1;
}
for (i = 0; i < NSects; i++) { /* look for special sectors */
if (Sects[i].property == 9) secret++;
if (Sects[i].property != 0) special++;
}
printf("\tMap...........(%d,%d) to (%d,%d)\n",xmin,ymin,xmax,ymax);
printf("\tThings........%ld (%ld bytes)\n",NThings,dir[THINGS].nbytes);
printf("\tLines.........%ld: %d 1-sided, %ld 2-sided (%ld bytes)\n",
NLines,one_sided,NLines-one_sided,dir[LINES].nbytes);
printf("\tSides.........%ld (%ld bytes)\n",NSides,dir[SIDES].nbytes);
printf("\tVertices......%ld: %d for lines, %ld for segs (%ld bytes)\n",
NVerts,mlv+1,NVerts-(mlv+1),dir[VERTS].nbytes);
printf("\tSegs..........%ld (%ld bytes)\n",NSegs,dir[SEGS].nbytes);
printf("\tSubsectors....%ld (%ld bytes)\n",NSsecs,dir[SSECTS].nbytes);
printf("\tNodes.........%ld (%ld bytes)\n",NNodes,dir[NODES].nbytes);
printf("\tSectors.......%ld: %d special, %d secret (%ld bytes)\n",
NSects,special,secret,dir[SECTS].nbytes);
for (i = 0; i < NRejects; i++)
if (Rejects[i] != 0) break;
printf("\tReject........%s (%ld bytes)\n",
i < NRejects ? "non-zeroed":"zeroed",dir[REJECTS].nbytes);
printf("\tBlockmap......%d x %d (%ld bytes)\n",
Blockmaps!=NULL?Blockmaps[2]:0,Blockmaps!=NULL?Blockmaps[3]:0,
dir[BLKMAPS].nbytes);
return TRUE;
}
/******************************************************************************
ROUTINE: directory(iwad)
WRITTEN BY: Robert Fenske, Jr.
CREATED: Sep. 1994
DESCRIPTION: This routine displays the resource directory for the
input file.
******************************************************************************/
#if defined(ANSI_C)
int directory(register WAD_INFO *iwad)
#else
int directory(iwad)
register WAD_INFO *iwad;
#endif
{
char name[20];
char *periods = "....................";
int n = 0; /* count of level parts */
long c; /* # items / entry */
register int e;
for (e = 0; e < iwad->head.count; e++) { /* scan resource directory */
sprintf(name,"%s%-.*s",
n ? " " : "", /* indent if part of level */
(int)sizeof(iwad->dir[e].name),iwad->dir[e].name);
if (1 == sscanf(iwad->dir[e].name,"E%*dM%d",&n) ||
1 == sscanf(iwad->dir[e].name,"MAP%d",&n)) n = ALL;
if (n > 0) n--;
printf("\t%s%.*s%ld bytes",
name,(int)(strlen(periods)-strlen(name)),periods,iwad->dir[e].nbytes);
if ((c = resource_count(&iwad->dir[e])) < iwad->dir[e].nbytes)
printf(" (%ld)",c);
printf("\n");
}
return TRUE;
}
/******************************************************************************
ROUTINE: extract(iwad,list)
WRITTEN BY: Robert Fenske, Jr.
CREATED: June 1994
DESCRIPTION: This routine extracts the named resources in the input
list from the input file. It manipulates the resource
directory so that only those extracted resources are
present in the directory. If any of the extracted
resources are E#M#, all resources associated with that
level are extracted. If the input list has a leading
exclamation point (!), then all resources not in the
list are extracted.
******************************************************************************/
#if defined(ANSI_C)
int extract(register WAD_INFO *iwad, char *list)
#else
int extract(iwad,list)
register WAD_INFO *iwad;
char *list;
#endif
{
char name[sizeof(iwad->dir[0].name)+1+1];
char *elist = blockmem(char,strlen(list)+1+1);
int i, n;
boolean find = TRUE; /* positive extract flag */
register int r = 0; /* # extracted resources */
register int e = 0;
if (list[0] == '!') { /* means to extract all */
find = !find; /* resources not specified */
list = &list[1];
}
strcat(strcat(strcpy(elist,","),list),","); /* bracket list w/commas */
while (e < iwad->head.count) { /* scan resource directory */
sprintf(name,",%-.*s",(int)(sizeof(iwad->dir[e].name)),iwad->dir[e].name);
if ((strstr(elist,name) != NULL && /* found one in list */
0 <= sscanf(strstr(elist,name),",%*[^,]%n",&n) &&
n == strlen(name)) == find) {
printf("%s...",&name[1]);
if (1 == sscanf(name,",E%*dM%d",&i) ||
1 == sscanf(name,",MAP%d",&i)) n = ALL;/* get all w/ E#M# or MAP## */
else n = 1; /* get this resource */
for (i = 0; i < n; i++, e++) {
blockcopy(&iwad->dir[r],&iwad->dir[e],sizeof(iwad->dir[e]));
if (r == 0)
iwad->dir[r].offset = sizeof iwad->head;
else
iwad->dir[r].offset = iwad->dir[r-1].offset + iwad->dir[r-1].nbytes;
if (iwad->data[e] == NULL) wad_read(iwad,e,1L<<0);
iwad->data[r] = iwad->data[e];
iwad->count[r] = iwad->count[e];
iwad->changed[r++] = TRUE;
}
}else
if (1 == sscanf(name,",E%*dM%d",&i) ||
1 == sscanf(name,",MAP%d",&i)) e += ALL;
else e += 1;
}
iwad->head.count = r; /* new count of resources */
iwad->head.ident[0] = 'P'; /* make sure it's a PWAD */
blockfree(elist);
return r > 0;
}
/******************************************************************************
ROUTINE: substitute(iwad,list)
WRITTEN BY: Robert Fenske, Jr.
CREATED: June 1994
DESCRIPTION: This routine substitutes the resources in the input
file with any that are found in the input list. Any
unique resources in the input list are ignored.
******************************************************************************/
#if defined(ANSI_C)
int substitute(register WAD_INFO *iwad, char *list)
#else
int substitute(iwad,list)
register WAD_INFO *iwad;
char *list;
#endif
{
char sfile[256]; /* file to substitute from */
int n;
register WAD_INFO *winfo;
register int e, i, r;
while (list != NULL && 1 == sscanf(list,"%[^,],",sfile)) {
winfo = wad_open(sfile,TRUE,FALSE);
if (winfo == NULL) {
fprintf(stderr,"unable to open %s for reading\n",sfile);
return FALSE;
}
printf("%s...",sfile); /* substituting from this */
for (r = 0; r < winfo->head.count; r++) {
for (e = 0; e < iwad->head.count; e++)
if (strncmp(winfo->dir[r].name,iwad->dir[e].name,
sizeof(winfo->dir[r].name)) == 0)
break; /* found a matching resource */
if (e < iwad->head.count) { /* substitute resource */
if (1 == sscanf(winfo->dir[r].name,"E%*dM%d",&n) ||
1 == sscanf(winfo->dir[r].name,"MAP%d",&n))
n = ALL; /* get all w/ E#M# or MAP## */
else
n = 1; /* get this resource */
(void)wad_read(winfo,r,~(~0L<<n));
for (i = 0; i < n; i++)
resource_update(iwad,e+i,winfo->data[r+i],winfo->count[r+i]);
r += n-1;
}
if (1 == sscanf(winfo->dir[r].name,"E%*dM%d",&n) ||
1 == sscanf(winfo->dir[r].name,"MAP%d",&n))
r += ALL-1;
}
wad_close(winfo);
list = strstr(list,",");
if (list != NULL) list++;
}
return TRUE;
}
/******************************************************************************
ROUTINE: merge(iwad,e,list)
WRITTEN BY: Robert Fenske, Jr.
CREATED: June 1994
DESCRIPTION: This routine merges the files in the input list with
the currently open input file referenced by iwad.
Any level data matching level data in the input file
(i.e., levels that have the same E#M#) is combined
into a single, larger level. Note that this combined
level will require the nodes, blockmap, and rejects to
be rebuilt. Any unique resources in the input merge
list are added to the input file as well. Non-unique
resources other than level data are not added, e.g. if
DEMO1 is in one of the merge list files and the input
file already as a DEMO1, it is not added to the input
file.
******************************************************************************/
#if defined(ANSI_C)
int merge(register WAD_INFO *iwad, int e, char *list)
#else
int merge(iwad,e,list)
register WAD_INFO *iwad;
int e;
char *list;
#endif
{
#define merge_resource(b,t,i,r,d1,c1,d2,c2) \
((b) = (char *)blockmem(t,((c1)+(c2))*sizeof(t)),\
blockcopy((b),(d1),(c1)*sizeof(t)),\
blockcopy(&(b)[(c1)*sizeof(t)],(d2),(c2)*sizeof(t)),\
resource_update((i),(r),(b),(c1)+(c2)),\
(c1) += (c2))
#define add_resource(b,t,d,c,r) \
((b) = (char *)blockmem(t,(c)),\
blockcopy((b),(d),((c)-1)*sizeof(t)),\
((t *)(b))[(c)-1] = (r),\
blockfree(d),\
(d) = (t *)(b))
char mfile[256]; /* file to merge */
int maxtag; /* maximum line/sector tag */
int maxvert; /* maximum input file vertex */
int maxwvert; /* max merge list file vert */
DOOM_LINE *wlines;
int i, n;
register char *buf;
register WAD_INFO *winfo;
register int r;
for (i = 0; i < ALL; i++) /* get any missing resources */
if (iwad->data[e+i] == NULL) (void)wad_read(iwad,e,1L<<i);
while (list != NULL && 1 == sscanf(list,"%[^,],",mfile)) {
winfo = wad_open(mfile,TRUE,FALSE);
if (winfo == NULL) {
fprintf(stderr,"unable to open %s for reading\n",mfile);
return FALSE;
}
printf("%s...",mfile); /* merging this file */
for (r = 0; r < winfo->head.count; r++)
if (strncmp(winfo->dir[r].name,iwad->dir[e+MAINS].name,
sizeof(winfo->dir[r].name)) == 0)
break;
if (r < winfo->head.count) { /* found matching level */
(void)wad_read(winfo,r,~(~0L<<ALL)); /* get all level data */
merge_resource(buf,DOOM_THING,iwad,e+THINGS,Things,NThings,
winfo->data[r+THINGS],winfo->count[r+THINGS]);
maxtag = maxvert = 0;
for (i = 0; i < NLines; i++) {
if (maxvert < Lines[i].fndx) maxvert = Lines[i].fndx;
if (maxvert < Lines[i].tndx) maxvert = Lines[i].tndx;
if (maxtag < Lines[i].sect_tag) maxtag = Lines[i].sect_tag;
}
maxwvert = 0;
wlines = (DOOM_LINE *)winfo->data[r+LINES];
for (i = 0; i < winfo->count[r+LINES]; i++) {
if (maxwvert < wlines[i].fndx) maxwvert = wlines[i].fndx;
if (maxwvert < wlines[i].tndx) maxwvert = wlines[i].tndx;
wlines[i].fndx += maxvert+1;
wlines[i].tndx += maxvert+1;
if (wlines[i].sect_tag != 0)
wlines[i].sect_tag += maxtag;
wlines[i].rsidndx += NSides;
if (wlines[i].lsidndx != -1) wlines[i].lsidndx += NSides;
}
merge_resource(buf,DOOM_LINE,iwad,e+LINES,Lines,NLines,
winfo->data[r+LINES],winfo->count[r+LINES]);
for (i = 0; i < winfo->count[r+SIDES]; i++)
((DOOM_SIDE *)winfo->data[r+SIDES])[i].sectndx += NSects;
merge_resource(buf,DOOM_SIDE,iwad,e+SIDES,Sides,NSides,
winfo->data[r+SIDES],winfo->count[r+SIDES]);
NVerts = maxvert+1;
merge_resource(buf,DOOM_VERT,iwad,e+VERTS,Verts,NVerts,
winfo->data[r+VERTS],maxwvert+1);
resource_update(iwad,e+SEGS,Segs,0L); /* kill these because they */
resource_update(iwad,e+SSECTS,Ssecs,0L); /* will have to be rebuilt */
resource_update(iwad,e+NODES,Nodes,0L);
for (i = 0; i < winfo->count[r+SECTS]; i++)
if (((DOOM_SECTOR *)winfo->data[r+SECTS])[i].line_tag != 0)
((DOOM_SECTOR *)winfo->data[r+SECTS])[i].line_tag += maxtag;
merge_resource(buf,DOOM_SECTOR,iwad,e+SECTS,Sects,NSects,
winfo->data[r+SECTS],winfo->count[r+SECTS]);
resource_update(iwad,e+REJECTS,Rejects,0L);/* these two will have to */
resource_update(iwad,e+BLKMAPS,Blockmaps,0L);/* be rebuilt also */
}
for (r = 0; r < winfo->head.count; r++) { /* search for unique rsrcs */
for (i = 0; i < iwad->head.count; i++)
if (strncmp(winfo->dir[r].name,iwad->dir[i].name,
sizeof(winfo->dir[r].name)) == 0)
break;
if (i == iwad->head.count) { /* add in new resource */
if (1 == sscanf(winfo->dir[r].name,"E%*dM%d",&n) ||
1 == sscanf(winfo->dir[r].name,"MAP%d",&n))
n = ALL; /* get all w/ E#M# or MAP## */
else
n = 1; /* get this resource */
(void)wad_read(winfo,r,~(~0L<<n));
for (i = 0; i < n; i++) {
add_resource(buf,DIR_ENTRY,iwad->dir,iwad->head.count+1,winfo->dir[r+i]);
add_resource(buf,char *,iwad->data,iwad->head.count+1,winfo->data[r+i]);
add_resource(buf,long,iwad->count,iwad->head.count+1,winfo->count[r+i]);
add_resource(buf,boolean,iwad->changed,iwad->head.count+1,TRUE);
iwad->head.count++;
}
r += n-1;
}
}
wad_close(winfo);
list = strstr(list,",");
if (list != NULL) list++;
}
return TRUE;
}